#include <server.h>
#include <chat.h>

#include <sqlite3.h>
#include <utility>
#include <algorithm>
#include <memory>


using namespace std;
using namespace Chat;



/*处理客户请求的线程*/
void* handleRequest(void* fd)
{
    int      sockfd, n;
    StateRet ret{};
    /*声明消息变量*/
    Message message{};
    /*声明消息缓冲区*/
    // unique_ptr<char> buf(new char[MAX_LINE]);
    char buf[MAX_LINE];

    sockfd = *(int*)(fd);


    // 接收用户发送的消息
    n = recv(sockfd, buf, sizeof(buf) + 1, 0);
    if (n <= 0) {
        // 关闭当前描述符，并清空描述符数组
        fflush(stdout);
        close(sockfd);
        *((int*)fd) = -1;
        printf("来自%s的退出请求！\n", inet_ntoa(message.sendAddr.sin_addr));
        return NULL;
    }   // if
    else {
        memcpy(&message, buf, sizeof(buf));
        /*为每个客户操作链接创建一个线程*/
        switch (message.msgType) {
        case MessageType::REGISTER: {
            printf("来自%s的注册请求！\n", inet_ntoa(message.sendAddr.sin_addr));
            ret             = ServerRegisterUser(message, sockfd);
            message         = Message{};
            message.msgType = MessageType::RESULT;
            message.msgRet  = ret;
            strcpy(message.content, stateMsg(ret).c_str());
            memset(buf, 0, MAX_LINE);
            memcpy(buf, &message, sizeof(message));
            /*发送操作结果消息*/
            send(sockfd, buf, sizeof(buf), 0);
            printf("注册：%s\n", stateMsg(ret).c_str());
            close(sockfd);
            *(int*)fd = -1;
            return NULL;
            break;
        }
        case MessageType::LOGIN: {
            printf("来自%s的登陆请求！\n", inet_ntoa(message.sendAddr.sin_addr));
            ret             = ServerLoginUser(message, sockfd);
            message         = Message{};
            message.msgType = MessageType::RESULT;
            message.msgRet  = ret;
            strcpy(message.content, stateMsg(ret).c_str());
            memset(buf, 0, MAX_LINE);
            memcpy(buf, &message, sizeof(message));      /*发送操作结果消息*/
            send(sockfd, buf, sizeof(buf), 0);
            printf("登录：%s\n", stateMsg(ret).c_str()); /*进入服务器处理聊天界面*/
            ServerEnterChat(&sockfd);
            break;
        }
        default:
            printf("unknown operation.\n");
            break;
        }
    }

    close(sockfd);
    *((int*)fd) = -1;
    return NULL;
}

StateRet ServerRegisterUser(const Message& msg, int sockfd)
{
    int ret{};
    /*声明用户需要的注册信息*/
    User user{};
    char buf[MAX_LINE]{};

    /*声明数据库变量*/
    sqlite3*      db{nullptr};
    sqlite3_stmt* stmt{nullptr};
    const char*   tail{nullptr};

    /*声明sql语句存储变量*/
    char sql[256]{};

    /*当前系统时间*/
    time_t timeNow{};

    /*存储操作结果消息*/
    Message message{};

    /*接收用户注册信息*/
    ret = recv(sockfd, buf, sizeof(user), 0);
    memcpy(&user, buf, sizeof(buf));
    user.userAddr = msg.sendAddr;
    user.sockfd   = sockfd;

    if (strlen(user.userName) > 20) {
        return StateRet::INVALID;
    }

    /*（1）打开数据库*/
    ret = sqlite3_open(DB_NAME.c_str(), &db);
    if (ret != SQLITE_OK) {
        printf("unable open database.\n");
        return StateRet::FAILED;
    }   // if
    printf("Opened database successfully.\n");

    /*（2）检查要注册用户名是否已存在？*/
    memset(sql, 0, sizeof(sql));
    sprintf(sql, "select * from User where userName = '%s';", (user.userName));


    ret = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail);
    if (ret != SQLITE_OK) {
        ret = sqlite3_step(stmt);
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        printf("database select fail!\n");
        return StateRet::FAILED;
    }   // if
    /*执行*/
    ret = sqlite3_step(stmt);
    // 如果有数据则返回SQLITE_ROW，当到达末尾返回SQLITE_DONE
    while (ret == SQLITE_ROW) {
        ret = sqlite3_step(stmt);
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return StateRet::FAILED;
    }
    /*销毁句柄，关闭数据库*/
    sqlite3_finalize(stmt);

    /*执行插入操作*/
    memset(sql, 0, sizeof(sql));
    time(&timeNow);
    sprintf(sql,
            "insert into User(userName , password , userAddr , sockfd , speak , registerTime)\
			values('%s','%s','%s',%d, %d , '%s');",
            user.userName,
            user.password,
            inet_ntoa(user.userAddr.sin_addr),
            user.sockfd,
            (int)Flag::YES,
            asctime(gmtime(&timeNow)));

    ret = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail);
    if (ret != SQLITE_OK) {
        ret = sqlite3_step(stmt);
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return StateRet::FAILED;
    }   // if

    /*顺利注册*/
    ret = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    /*注册成功*/
    return StateRet::SUCCESS;
}

StateRet ServerLoginUser(const Message& msg, int sockfd)
{
    int ret;
    /*声明用户信息*/
    User user;
    char buf[MAX_LINE];

    /*声明数据库变量*/
    sqlite3*      db;
    sqlite3_stmt* stmt;
    const char*   tail;

    /*声明sql语句存储变量*/
    char sql[128]{};


    /*存储操作结果消息*/
    Message message{};

    /*接收用户信息*/
    recv(sockfd, buf, sizeof(user), 0);
    memset(&user, 0, sizeof(user));
    memcpy(&user, buf, sizeof(buf));
    user.userAddr = msg.sendAddr;
    user.sockfd   = sockfd;

    /*查看在线用户列表，该用户是否已在线*/
    auto item = std::find_if(userList.cbegin(),
                             userList.cend(),
                             [&user](User x) { return (strcmp(x.userName, user.userName) == 0); });
    if (item != userList.cend()) {
        return StateRet::ALREADY_ONLINE;
    }

    /*（1）打开数据库*/
    ret = sqlite3_open(DB_NAME.c_str(), &db);
    if (ret != SQLITE_OK) {
        printf("unable open database.\n");
        return StateRet::FAILED;
    }   // if

    /*（2）检查登陆用户名和密码*/
    memset(sql, 0, sizeof(sql));
    sprintf(sql,
            "select * from User where userName='%s' and password='%s';",
            user.userName,
            user.password);

    ret = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail);
    if (ret != SQLITE_OK) {
        ret = sqlite3_step(stmt);
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        printf("database select fail!\n");
        return StateRet::FAILED;
    }   // if
    /*执行*/
    ret = sqlite3_step(stmt);
    // 如果有数据则返回SQLITE_ROW，当到达末尾返回SQLITE_DONE
    while (ret == SQLITE_ROW) {
        ret = sqlite3_step(stmt);
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        /*如果登陆操作成功，添加到在线用户链表*/
        userList.push_back(user);
        return StateRet::SUCCESS;
    }   // while
    /*销毁句柄，关闭数据库*/
    sqlite3_finalize(stmt);
    sqlite3_close(db);

    return StateRet::FAILED;
}
